Skip to content

Conversation

@cemilcolak
Copy link

@cemilcolak cemilcolak commented Sep 21, 2025

  • Change: Update find_codex_home to resolve CODEX_HOME in this order:
    1. Project-local .codex/ in the current working directory, if present
    2. CODEX_HOME environment variable, if set
    3. Default ~/.codex
  • Behavior: When a project contains .codex/, Codex reads/writes config.toml/config.json, auth.json, logs, history, etc. from that folder, effectively overriding the global ~/.codex/ without needing flags.
  • Docs: Updated to reflect the new precedence:
    • codex-rs/README.md: Added “Project-local overrides” note
    • docs/config.md: Clarified CODEX_HOME resolution order
    • docs/authentication.md: Clarified where auth.json is read/written

Motivation

  • Per-project isolation: Teams often need project-scoped settings (model, provider, auth) that shouldn’t bleed into other work. Resolving CODEX_HOME to a project’s .codex/ creates a clean, self-contained environment for each repo.
  • Developer experience: Switching between projects no longer requires exporting CODEX_HOME or passing flags. Just cd into the project and run codex — it automatically picks up the right config/auth.
  • Cost and policy awareness: Different projects may target different models, budgets, or retention policies. With project-local .codex/, cost controls, history settings, and provider choices live alongside the codebase, making spend, privacy, and
    compliance easier to reason about per project.
  • On-prem and special environments: Some projects must run on-prem or behind strict network policies. A project’s .codex/ can pin a specific provider/baseURL and auth configuration so teammates don’t reconfigure global settings or remember one-off
    flags.
  • Collaboration ready: Committing a template .codex/ (without secrets) documents expected defaults for contributors. Each developer adds their own auth.json locally, and everyone gets consistent behavior out of the box.
  • Backwards compatible: If .codex/ is absent, behavior is unchanged and global ~/.codex/ (or CODEX_HOME) continues to work as before.

Testing

  • Targeted (run in codex-rs):
    • just fmt
    • just fix -p codex-core
    • cargo test -p codex-core
  • Results:
running 249 tests
test bash::tests::rejects_parentheses_and_subshells ... ok
...
test unified_exec::tests::unified_exec_timeouts ... ok

test result: ok. 247 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 12.35s

     Running tests/all.rs (target/debug/deps/all-e874685d3c78bab3)

running 58 tests
test suite::client::azure_responses_request_includes_store_and_reasoning_ids ... ok
...
test suite::cli_stream::integration_creates_and_checks_session_file ... ok

test result: ok. 56 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 31.25s

     Running tests/chat_completions_payload.rs (target/debug/deps/chat_completions_payload-e1df0bcf8b73eea3)

running 8 tests
test suppresses_duplicate_assistant_messages ... ok
...
test attaches_reasoning_to_local_shell_call ... ok

test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s

     Running tests/chat_completions_sse.rs (target/debug/deps/chat_completions_sse-4c700c340a0c495e)

running 5 tests
test streams_reasoning_before_tool_call ... ok
...
test streams_reasoning_from_string_delta ... ok

test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s

Manual sanity

  • Create a project-local config and auth:
    • mkdir -p .codex
    • echo 'model = "o3"' > .codex/config.toml
    • echo '{"OPENAI_API_KEY": "your project custom api key"}' > .codex/auth.json
    • echo ".codex/" >> .gitignore
  • Run codex inside this directory and verify it uses project settings (check effective model/provider or logs under .codex/log/).
  • Remove or rename .codex/ and verify it falls back to global ~/.codex/ (or CODEX_HOME env).

Changed files

  • codex-rs/core/src/config.rs
  • codex-rs/README.md
  • docs/config.md
  • docs/authentication.md

Notes

  • No changes were made to CODEX_SANDBOX_* logic.
  • CLI behavior with --config remains unchanged; this feature only adds automatic project-local override.
  • Fixes issue local project .codex directory support #3706.
  • Adding .codex files to .gitignore is the developer's responsibility.

@github-actions
Copy link

github-actions bot commented Sep 21, 2025

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@cemilcolak
Copy link
Author

I have read the CLA Document and I hereby sign the CLA

github-actions bot added a commit that referenced this pull request Sep 21, 2025
@cemilcolak cemilcolak mentioned this pull request Sep 21, 2025
@cemilcolak cemilcolak mentioned this pull request Sep 27, 2025
@rafagsiqueira
Copy link

Thank you for this! Looking forward to it.

@cemilcolak cemilcolak force-pushed the feat/project-local-codex-home branch from 15f45cf to fa8199b Compare September 30, 2025 14:35
@rickythefox
Copy link

Merge this please, it's an essential piece of functionality.

@cemilcolak
Copy link
Author

This two commit, extends the /status panel to display which codex_home the project is currently running with.
In addition, several test and formatting improvements have been made to ensure consistency across snapshots and UI rendering.

Details

  • Added the home field to the Status card data model and updated the label list to include a new “Home” row, formatted using format_directory_display for consistency with the Directory line.
  • Implemented sanitize_field logic to normalize Home and Directory values in snapshot tests, ensuring that replacements maintain the correct card width.
  • Updated snapshot sanitizer to apply the normalization logic to both Home and Directory fields.
  • Regenerated all related status snapshots to include the new Home line with proper alignment.
  • Ran just fmt, just fix -p codex-tui, and cargo test -p codex-tui to validate and format all changes.

CODEX_HOME: ~/codex

/status

╭────────────────────────────────────────────────────────────────────────╮
│  >_ OpenAI Codex (v0.0.0)                                              │
│                                                                        │
│  Model:            gpt-5-codex (reasoning high, summaries auto)        │
│  Home:             ~/.codex                                            │
│  Directory:        ~/Projects/opensource/codex/codex-rs                │
│  Approval:         on-request                                          │
│  Sandbox:          workspace-write                                     │
│  Agents.md:        ../AGENTS.md                                        │
│  Account:          API key configured (run codex login to use ChatGPT) │
│  Session:          xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx                │
│                                                                        │
│  Token usage:      0 total  (0 input + 0 output)                       │
│  Context window:   100% left (0 used / 272K)                           │
│  Limits:           send a message to load usage data                   │
╰────────────────────────────────────────────────────────────────────────╯

A folder named .codex was opened in the main project directory.
CODEX_HOME: project_folder_path/.codex

/status

╭────────────────────────────────────────────────────────────────────────╮
│  >_ OpenAI Codex (v0.0.0)                                              │
│                                                                        │
│  Model:            gpt-5-codex (reasoning none, summaries auto)        │
│  Home:             ~/Projects/opensource/codex/codex-rs/.codex         │
│  Directory:        ~/Projects/opensource/codex/codex-rs                │
│  Approval:         on-request                                          │
│  Sandbox:          read-only                                           │
│  Agents.md:        ../AGENTS.md                                        │
│  Account:          API key configured (run codex login to use ChatGPT) │
│  Session:          xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx                │
│                                                                        │
│  Token usage:      0 total  (0 input + 0 output)                       │
│  Context window:   100% left (0 used / 272K)                           │
│  Limits:           send a message to load usage data                   │
╰────────────────────────────────────────────────────────────────────────╯

@kervel
Copy link

kervel commented Oct 16, 2025

github spec-kit asks you to set CODEX_HOME when using it in a project. This would make that unnessecary.

@cemilcolak
Copy link
Author

@kervel Yes, that's true; the goal is to create a project-specific conf structure. Under normal use, if there's no .codex folder in the project, the system will work as before without any impact.

@bolinfest
Copy link
Collaborator

The challenge with supporting an in-repo .codex folder for configuration (which I do believe is a good thing for sharing configuration across contributors to a project) is that, using the default workspace-write sandbox setting, that means that Codex could update its own config.toml file.

One could imagine a situation where someone tries to trick Codex into adding sandbox_mode = "danger-full-access" to .codex/config.toml in the repo such that the next time codex is invoked, it would operate without a sandbox.

Today, with Seatbelt on macOS, we have the ability to make, e.g., the .git folder within a repo read-only while the rest of the repo is writable, as verified here:

fn create_seatbelt_args_with_read_only_git_subpath() {

Though the Landlock/Seccomp sandbox we use on Linux does not support this today. My understanding is that it does not allow a subfolder (.git in this case) to have a more restrictive policy than the parent folder (the writable Git repo) unless the folders are on different filesystems.

All that is to say, before supporting such a feature, I think we need a reasonable mitigation for the scenario described above (be it sandboxing or in-repo config.toml supporting only a subset of the full set of config options).

@bolinfest
Copy link
Collaborator

Related: #2308.

@etraut-openai
Copy link
Collaborator

@cemilcolak, after some internal discussion, we've decided to close this PR. We really appreciate that you took the time to implement this. This is a highly-requested feature, and we'd love to get it into the hands of codex users. However, as bolinfest mentions above, the difficult part is in working through the security and sandboxing implications of the feature. That's going to require some deep thought and design work. Once we have those questions answered and the requisite sandboxing enhancements in place, it should be straightforward to implement the code to handle project-local features. We can use your code as a good PoC (proof of concept).

@github-actions github-actions bot locked and limited conversation to collaborators Nov 7, 2025
@openai openai unlocked this conversation Nov 7, 2025
@cemilcolak
Copy link
Author

@bolinfest @etraut-openai Thanks for the explanation. I’ve been using this feature for about 1.5 months and it’s been very helpful in practice. I understand your concerns, and I’ll also think more about the security side. I’m happy to help again once the design is ready.

youta7 added a commit to youta7/ta-codex that referenced this pull request Nov 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants